#pragma once

#if defined(__GNUC__) || (defined(__clang__) && !defined(_MSC_VER))

#define ZENO_LIKELY(x) (__builtin_expect(!!(x), 1))
#define ZENO_UNLIKELY(x) (__builtin_expect(!!(x), 0))
#define ZENO_RESTRICT __restrict__
#define ZENO_NOINLINE __attribute__((__noinline__))
#define ZENO_FORCEINLINE __inline__ __attribute__((__always_inline__))
#define ZENO_NORETURN __attribute__((__noreturn__))
#define ZENO_ASSUME_ALIGNED(x, n) ((void *)__builtin_assume_aligned((void *)(x), (n)))
#define ZENO_GNUC_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
#define ZENO_MSVC_DECLSPEC(...)
#define ZENO_PRAGMA(...) _Pragma(#__VA_ARGS__)
#define ZENO_GNUC_PRAGMA(...) _Pragma("GCC " #__VA_ARGS__)
#define ZENO_MSVC_PRAGMA(...)
#define ZENO_ENABLE_IF_GNUC(...) __VA_ARGS__
#define ZENO_ENABLE_IF_MSVC(...)
#define ZENO_UNREACHABLE() __builtin_unreachable()
#define ZENO_DEBUG_BREAK() __builtin_trap()
#define ZENO_DO_NOT_OPTIMIZE() __asm__ __volatile__ ("" ::: "cc", "memory")

#if defined(__clang__) && !defined(_MSC_VER)
#define ZENO_GNUC_ONLY_ATTRIBUTE(...)
#define ZENO_ENABLE_IF_GNUC_ONLY(...)
#define ZENO_CLANG_PRAGMA(...) _Pragma("clang " #__VA_ARGS__)
#define ZENO_ENABLE_IF_CLANG(...) __VA_ARGS__
#define ZENO_ASSUME(x) __builtin_assume(x)
#else
#define ZENO_GNUC_ONLY_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
#define ZENO_ENABLE_IF_GNUC_ONLY(...) __VA_ARGS__
#define ZENO_CLANG_PRAGMA(...)
#define ZENO_ENABLE_IF_CLANG(...)
#define ZENO_ASSUME(x) __attribute__((__assume__(x)))
#endif

#elif defined(_MSC_VER)

#include <intrin.h>

#define ZENO_LIKELY(x) (x)
#define ZENO_UNLIKELY(x) (x)
#define ZENO_RESTRICT __restrict
#define ZENO_NOINLINE __declspec(noinline)
#define ZENO_FORCEINLINE __forceinline
#define ZENO_NORETURN __declspec(noreturn)
#define ZENO_ASSUME_ALIGNED(x, n) ((void *)((unsigned long long)(void *)(x) & (n - 1)))
#define ZENO_GNUC_ATTRIBUTE(...)
#define ZENO_MSVC_DECLSPEC(...) __declspec(__VA_ARGS__)
#define ZENO_PRAGMA(...) _Pragma(#__VA_ARGS__)
#define ZENO_GNUC_PRAGMA(...)
#define ZENO_GNUC_ONLY_PRAGMA(...)
#define ZENO_CLANG_PRAGMA(...)
#define ZENO_MSVC_PRAGMA(...) __pragma(__VA_ARGS__)
#define ZENO_ENABLE_IF_GNUC(...)
#define ZENO_ENABLE_IF_GNUC_ONLY(...)
#define ZENO_ENABLE_IF_CLANG(...)
#define ZENO_ENABLE_IF_MSVC(...) __VA_ARGS__
#define ZENO_ASSUME(x) __assume(x)
#define ZENO_UNREACHABLE() __assume(0)
#define ZENO_DEBUG_BREAK() __debugbreak()
#define ZENO_DO_NOT_OPTIMIZE() __nop()

#else

#define ZENO_LIKELY(x) (x)
#define ZENO_UNLIKELY(x) (x)
#define ZENO_RESTRICT
#define ZENO_NOINLINE
#define ZENO_FORCEINLINE inline
#define ZENO_NORETURN [[noreturn]]
#define ZENO_ASSUME_ALIGNED(x, n) ((void *)((unsigned long long)(void *)(x) & (n - 1)))
#define ZENO_GNUC_ATTRIBUTE(...)
#define ZENO_MSVC_DECLSPEC(...)
#define ZENO_PRAGMA(...) _Pragma(#__VA_ARGS__)
#define ZENO_GNUC_PRAGMA(...)
#define ZENO_CLANG_PRAGMA(...)
#define ZENO_MSVC_PRAGMA(...)
#define ZENO_ENABLE_IF_GNUC(...)
#define ZENO_ENABLE_IF_CLANG(...)
#define ZENO_ENABLE_IF_MSVC(...)
#define ZENO_ASSUME(x) [[assume(x)]]
#define ZENO_UNREACHABLE() [[assume(0)]]
#define ZENO_DEBUG_BREAK()
#define ZENO_DO_NOT_OPTIMIZE() do { if (volatile int __x = 0) { (void)__x; } } while (0)

#endif

#if defined(__INTEL_COMPILER)
#define ZENO_PUSH_WARN \
    _Pragma("warning (push)")
#define ZENO_POP_WARN \
    _Pragma("warning (pop)")
#elif defined(__clang__) && !defined(_MSC_VER)
#define ZENO_PUSH_WARN \
    _Pragma("clang diagnostic push") \
    _Pragma("clang diagnostic ignored \"-Wall\"") \
    _Pragma("clang diagnostic ignored \"-Wpedantic\"") \
    _Pragma("clang diagnostic ignored \"-Wextra\"") \
    _Pragma("clang diagnostic ignored \"-Wconversion\"") \
    _Pragma("clang diagnostic ignored \"-Wnarrowing\"") \
    _Pragma("clang diagnostic ignored \"-Wsuggest-override\"") \
    _Pragma("clang diagnostic ignored \"-Wnon-virtual-dtor\"") \
    _Pragma("clang diagnostic ignored \"-Wuninitialized\"") \
    _Pragma("clang diagnostic ignored \"-Wmissing-declarations\"") \
    _Pragma("clang diagnostic ignored \"-Wunused\"") \
    _Pragma("clang diagnostic ignored \"-Wunused-function\"") \
    _Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") \
    _Pragma("clang diagnostic ignored \"-Wmisleading-indentation\"") \
    _Pragma("clang diagnostic ignored \"-Wshift-negative-value\"") \
    _Pragma("clang diagnostic ignored \"-Wimplicit-fallthrough\"") \
    _Pragma("clang diagnostic ignored \"-Wnull-dereference\"")
#define ZENO_POP_WARN \
    _Pragma("clang diagnostic pop")
#elif defined(__GNUC__)
#define ZENO_PUSH_WARN \
    _Pragma("GCC diagnostic push") \
    _Pragma("GCC diagnostic ignored \"-Wall\"") \
    _Pragma("GCC diagnostic ignored \"-Wextra\"") \
    _Pragma("GCC diagnostic ignored \"-Wconversion\"") \
    _Pragma("GCC diagnostic ignored \"-Wnarrowing\"") \
    _Pragma("GCC diagnostic ignored \"-Wnon-virtual-dtor\"") \
    _Pragma("GCC diagnostic ignored \"-Wsuggest-override\"") \
    _Pragma("GCC diagnostic ignored \"-Wuninitialized\"") \
    _Pragma("GCC diagnostic ignored \"-Wmissing-declarations\"") \
    _Pragma("GCC diagnostic ignored \"-Wunused\"") \
    _Pragma("GCC diagnostic ignored \"-Wunused-function\"") \
    _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") \
    _Pragma("GCC diagnostic ignored \"-Wmisleading-indentation\"") \
    _Pragma("GCC diagnostic ignored \"-Wshift-negative-value\"") \
    _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") \
    _Pragma("GCC diagnostic ignored \"-Wnull-dereference\"")
#define ZENO_POP_WARN \
    _Pragma("GCC diagnostic pop")
#elif defined _MSC_VER
#define ZENO_PUSH_WARN \
    __pragma(warning(push))
#define ZENO_POP_WARN \
    __pragma(warning(pop))
#else
#define ZENO_PUSH_WARN
#define ZENO_POP_WARN
#endif

#define ZENO_WEAK_SYMBOL ZENO_GNUC_ONLY_ATTRIBUTE(__weak__)
#define ZENO_WEAK_ALIAS(...) ZENO_GNUC_ONLY_ATTRIBUTE(__weak__, __alias__(#__VA_ARGS__))
#define ZENO_HOT_FN ZENO_GNUC_ATTRIBUTE(__hot__)
#define ZENO_COLD_FN ZENO_GNUC_ATTRIBUTE(__cold__)
#define ZENO_CONST_FN ZENO_GNUC_ATTRIBUTE(__const__)
#define ZENO_PURE_FN ZENO_GNUC_ATTRIBUTE(__pure__)
#define ZENO_OPTIMIZE_FN(...) ZENO_GNUC_ONLY_ATTRIBUTE(__optimize__(#__VA_ARGS__))
#define ZENO_TARGET_FN(...) ZENO_GNUC_ATTRIBUTE(__target__(#__VA_ARGS__))
#define ZENO_TARGET_CLONES(...) ZENO_GNUC_ATTRIBUTE(__target_clones__(__VA_ARGS__))
#define ZENO_MSVC_DLLEXPORT ZENO_MSVC_DECLSPEC(dllexport)
#define ZENO_MSVC_DLLIMPORT ZENO_MSVC_DECLSPEC(dllimport)
#define ZENO_GNUC_VISIBILITY(...) ZENO_GNUC_ATTRIBUTE(__visibility__(#__VA_ARGS__))
